﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.ESB.GlobalPropertyContext;
using Microsoft.Practices.ESB.Resolver;
using Microsoft.Practices.ESB.Resolver.BRE;
using Microsoft.Practices.ESB.Resolver.Itinerary;
using Microsoft.Practices.ESB.Resolver.Itinerary.Facts;
using Microsoft.Practices.ESB.Exception.Management;
using Microsoft.Practices.ESB.Resolver.Itinerary.Facts.Repository;
using Microsoft.Practices.ESB.Resolver.Itinerary.DataAccess;
using Microsoft.BizTalk.Message.Interop;
using Microsoft.BizTalk.Component.Interop;
using Microsoft.XLANGs.BaseTypes;
using System.Reflection;
using System.Runtime.InteropServices;

namespace BizTalk.ESB.Extensions.Resolvers
{
    public class ItineraryCorrelationResolution
    {
        public string ContextProprty { get; set; }

        public void SetCorrelationContextProperty(string PropertyNamespace, string PropertyName)
        {
            if (!string.IsNullOrEmpty(PropertyNamespace) && !string.IsNullOrEmpty(PropertyName))
            {
                this.ContextProprty = PropertyNamespace + "#" + PropertyName;
            }
        }
    }

    public class ItineraryCorrelationResolutionManager
    {
        public static BRE CreateResolverDescriptor(String config, String resolver)
        {
            BRE breWrapper;

            if (config == null)
            {
                throw new ArgumentNullException("config");
            }
            if (resolver == null)
            {
                throw new ArgumentNullException("resolver");
            }

            Dictionary<String, String> facts = null;
            try
            {
                BRE breTemp = new BRE();
                breTemp.useMsg = false;
                facts = ResolverMgr.GetFacts(config, resolver);
                breTemp.policy = ResolverMgr.GetConfigValue(facts, true, "policy");
                breTemp.version = ResolverMgr.GetConfigValue(facts, false, "version");
                Boolean useMessage, recognizeMessage;
                breTemp.useMsgSpecified = Boolean.TryParse(
                    ResolverMgr.GetConfigValue(facts, false, "useMsg")
                    , out useMessage);
                breTemp.recognizeMessageFormatSpecified = Boolean.TryParse(
                    ResolverMgr.GetConfigValue(facts, false, "recognizeMessageFormat")
                    , out recognizeMessage);
                breTemp.useMsg = useMessage;
                breTemp.recognizeMessageFormat = recognizeMessage;

                breWrapper = breTemp;
            }
            catch (Exception e)
            {
                EventLogger.Write(MethodBase.GetCurrentMethod(), e);
                throw;
            }
            finally
            {
                if (facts != null)
                {
                    facts.Clear();
                    facts = null;
                }
            }

            return breWrapper;
        }

        public static void SetResolverDictionary(ItineraryCorrelationResolution resolution, Dictionary<String, String> dictionary)
        {
            try
            {
                dictionary.Add("Resolver.CorrelationContextSource", resolution.ContextProprty);
            }
            catch (Exception e)
            {
                System.Diagnostics.Trace.WriteLine("Error!!! " + e.Message);
            }
        }

        //public static void SetContext(ItineraryListResolution resolution, IBaseMessage message, IPipelineContext pipelineContext)
        //{
        //    if (pipelineContext == null)
        //    {
        //        throw new ArgumentNullException("pipelineContext");
        //    }
        //    if (message == null)
        //    {
        //        throw new ArgumentNullException("message");
        //    }
        //    if (resolution == null)
        //    {
        //        throw new ArgumentNullException("resolution");
        //    }

        //    try
        //    {
        //        resolution.DocumentSpecStrongName = ((String)message.Context.Read(BtsProperties.SchemaStrongName.Name, BtsProperties.SchemaStrongName.Namespace)) ?? String.Empty;
        //        EventLogger.Write("Document strong name is {0} after first context read", new Object[] { resolution.DocumentSpecStrongName });
        //        resolution.MessageType = ((String)message.Context.Read(BtsProperties.MessageType.Name, BtsProperties.MessageType.Namespace)) ?? String.Empty;
        //        EventLogger.Write("Document message type is {0} after first context read", new Object[] { resolution.DocumentSpecStrongName });

        //        if (String.IsNullOrEmpty(resolution.DocumentSpecStrongName) == false)
        //        {
        //            Int32 index = resolution.DocumentSpecStrongName.IndexOf(",", StringComparison.CurrentCultureIgnoreCase);
        //            if ((index > 0) && (index < resolution.DocumentSpecStrongName.Length))
        //            {
        //                resolution.DocumentSpecName = resolution.DocumentSpecStrongName.Substring(0, index);
        //            }
        //            else
        //            {
        //                resolution.DocumentSpecName = resolution.DocumentSpecStrongName;
        //            }

        //            try
        //            {
        //                IDocumentSpec docSpecByName = pipelineContext.GetDocumentSpecByName(resolution.DocumentSpecStrongName);
        //                if (docSpecByName != null)
        //                {
        //                    resolution.DocumentSpecName = docSpecByName.DocSpecName;
        //                }
        //                if (String.IsNullOrEmpty(resolution.MessageType))
        //                {
        //                    resolution.MessageType = docSpecByName.DocType;
        //                }
        //            }
        //            catch (DocumentSpecException docspecEx)
        //            {
        //                System.Diagnostics.Trace.WriteLine("ERROR: " + docspecEx.Message);
        //            }
        //            catch (COMException comEx)
        //            {
        //                System.Diagnostics.Trace.WriteLine("ERROR" + comEx.Message);
        //            }
        //        }
        //        EventLogger.Write("Document name is {0} after check.", new Object[] { resolution.DocumentSpecName });
        //        EventLogger.Write("Document strong name is {0} after check.", new Object[] { resolution.DocumentSpecStrongName });
        //        EventLogger.Write("Document message type is {0} after check.", new Object[] { resolution.MessageType });

        //    }
        //    catch (Exception e)
        //    {
        //        EventLogger.Write(MethodBase.GetCurrentMethod(), e);
        //        throw;
        //    }
        //}

        //public static void SetContext(ItineraryListResolution resolution, XLANGMessage message)
        //{
        //    if (message == null)
        //    {
        //        throw new ArgumentNullException("message");
        //    }
        //    if (resolution == null)
        //    {
        //        throw new ArgumentNullException("resolution");
        //    }
        //    try
        //    {
        //        resolution.MessageType = ((String)ItineraryListResolutionManager.GetMsgProperty(message
        //            , typeof(BTS.MessageType))) ?? String.Empty;
        //        resolution.DocumentSpecStrongName = ((String)ItineraryListResolutionManager.GetMsgProperty(message
        //            , typeof(BTS.SchemaStrongName))) ?? String.Empty;
        //        if (String.IsNullOrEmpty(resolution.DocumentSpecStrongName) == false)
        //        {
        //            Int32 index = resolution.DocumentSpecStrongName.IndexOf(",", StringComparison.CurrentCultureIgnoreCase);
        //            if ((index > 0) && (index < resolution.DocumentSpecStrongName.Length))
        //            {
        //                resolution.DocumentSpecStrongName = resolution.DocumentSpecStrongName.Substring(0, index);
        //            }
        //        }
        //    }
        //    catch (Exception e)
        //    {
        //        EventLogger.Write(MethodBase.GetCurrentMethod(), e);
        //        throw;
        //    }
        //}

        //private static Object GetMsgProperty(XLANGMessage message, Type property)
        //{
        //    Object prop;
        //    if (message == null)
        //    {
        //        throw new ArgumentNullException("message");
        //    }
        //    if (property == null)
        //    {
        //        throw new ArgumentNullException("property");
        //    }
        //    Object PropertyValue = null;
        //    try
        //    {
        //        PropertyValue = message.GetPropertyValue(property);
        //        prop = PropertyValue;
        //    }
        //    catch (Exception e)
        //    {
        //        EventLogger.Write(MethodBase.GetCurrentMethod(), e);
        //        throw;
        //    }
        //    finally
        //    {
        //        if (PropertyValue != null)
        //        {
        //            PropertyValue = null;
        //        }
        //    }
        //    return prop;
        //}
    }

    public class ItineraryCorrelationStaticResolver : IResolveProvider
    {
        private const String ResolverName = "ITINERARYLINK-STATIC";

        public Dictionary<string, string> Resolve(ResolverInfo resolverInfo, XLANGMessage message)
        {
            // Create instance of ItineraryCorrelationResolution
            ItineraryCorrelationResolution itineraryCorrelationResolution = new ItineraryCorrelationResolution();

            // Call ResolveStatic
            return ResolveStatic(resolverInfo.Config, resolverInfo.Resolver, itineraryCorrelationResolution);
        }

        public Dictionary<string, string> Resolve(string config, string resolver, System.Xml.XmlDocument message)
        {
            // Create instance of ItineraryCorrelationResolution
            ItineraryCorrelationResolution itineraryCorrelationResolution = new ItineraryCorrelationResolution();

            // Call ResolveStatic
            return ResolveStatic(config, resolver, itineraryCorrelationResolution);
        }

        public Dictionary<string, string> Resolve(string config, string resolver, IBaseMessage message, IPipelineContext pipelineContext)
        {
            System.Diagnostics.Trace.WriteLine("In STATIC Resolver from Pipeline");

            // Create instance of ItineraryCorrelationResolution
            ItineraryCorrelationResolution itineraryCorrelationResolution = new ItineraryCorrelationResolution();

            // Call ResolveStatic
            return ResolveStatic(config, resolver, itineraryCorrelationResolution);
        }

        private static Dictionary<String, String> ResolveStatic(String config, String resolver, ItineraryCorrelationResolution resolution)
        {
            // DEBUG
            System.Diagnostics.Trace.WriteLine("CONFIG = " + config);
            System.Diagnostics.Trace.WriteLine("RESOLVER = " + resolver);

            Dictionary<String, String> resolverInfo = new Dictionary<String, String>();
            Dictionary<String, String> resolverDictionary = new Dictionary<String, String>();
            Dictionary<String, String> facts = null;

            // Add keys from config
            // Add keys from resolver string
            // Add keys from resolution
            if (!resolver.Contains(@":\"))
            {
                resolver = resolver + @":\";
            }
            try
            {
                System.Diagnostics.Trace.WriteLine("Getting resolver info for " + resolver);
                facts = ResolverMgr.GetFacts(config, resolver);
                resolution.ContextProprty = ResolverMgr.GetConfigValue(facts, true, "prop");
                ItineraryCorrelationResolutionManager.SetResolverDictionary(resolution, resolverDictionary);
                resolverInfo = resolverDictionary;
            }
            catch (Exception e)
            {
                EventLogger.Write(MethodBase.GetCurrentMethod(), e);
                throw;
            }
            finally
            {
                if (facts != null)
                {
                    facts.Clear();
                    facts = null;
                }
                if (resolution != null)
                {
                    resolution = null;
                }
                if (resolverDictionary != null)
                {
                    resolverDictionary = null;
                }
            }

            return resolverInfo;
        }
    }
}
